import * as os from "os";
import * as path from "path";
import * as fs from "fs";
import * as url from "url";

const AssemblerName = "dist/ZGAssembler.js";
let ConfigPath = url.fileURLToPath(import.meta.url);
ConfigPath = path.dirname(ConfigPath);
ConfigPath = path.join(ConfigPath, "config.json").replace(/\\/g, "/");

//#region 初始化
async function Initialization() {
	const assName = await CheckConfig();
	if (!assName)
		return;

	return await AssemblerInit(assName);
}

async function CheckConfig() {
	let config = { extensionFolder: "", assemblerDirName: "" };
	try {
		if (await CheckFile(ConfigPath) === "file")
			config = (await import(`file://${ConfigPath}`, { assert: { type: "json" } })).default;
	} catch (e) {
		console.error(e);
	}

	return await CheckExtensionPath(config);
}

/**保存配置，并返回插件位置 */
async function CheckExtensionPath(config) {
	let extensionPath = path.join(config.extensionFolder, config.assemblerDirName, AssemblerName);
	if (await CheckFile(extensionPath) === "file") {
		return extensionPath;
	}

	extensionPath = path.join(os.homedir(), ".vscode", "extensions");
	config.extensionFolder = extensionPath;
	const dirs = fs.readdirSync(extensionPath);

	config.assemblerDirName = "";
	for (let i = 0; i < dirs.length; i++) {
		const dir = dirs[i];
		if (dir.startsWith("zeng-ge.zg-assembler-")) {
			config.assemblerDirName = dir;
			extensionPath = path.join(extensionPath, dir, AssemblerName);
			break;
		}
	}

	if (!config.assemblerDirName) {
		console.error("找不到插件，请安装 \"ZG Assembler\"");
		return;
	}

	fs.writeFileSync(ConfigPath, JSON.stringify(config));
	return extensionPath.replace(/\\/g, "/");
}

async function CheckFile(filePath) {
	try {
		const stat = fs.statSync(filePath);
		if (stat.isDirectory()) {
			return "path";
		} else if (stat.isFile()) {
			return "file";
		}
	} catch {
		return "none";
	}
}
//#endregion 初始化

//#region 初始化编译器
/**编译器初始化 */
async function AssemblerInit(assemblerPath) {
	const { ZGAssembler } = (await import(`file://${assemblerPath}`)).default;

	let assembler = new ZGAssembler();

	assembler.fileUtils.Implement({
		ReadFile: (filePath) => {
			return new Promise((resolve, reject) => {
				fs.readFile(filePath, (error, data) => {
					if (error) {
						reject(error);
						return;
					}
					resolve(new Uint8Array(data.buffer));
				});
			});
		},

		SaveFile: (filePath, data) => {
			fs.writeFileSync(filePath, data);
		},

		GetFolderFiles: (foldPath) => {
			const files = fs.readdirSync(foldPath);
			/** @type {{name:string, type:"folder"|"file"}[]} */
			let result = [];
			for (let i = 0; i < files.length; i++) {
				const tempPath = path.join(foldPath, files[i]);
				const stat = fs.statSync(tempPath);
				if (stat.isDirectory()) {
					result.push({ name: tempPath, type: "folder" });
				} else {
					result.push({ name: tempPath, type: "file" });
				}
			}
			return result;
		},

		PathType: CheckFile,

		ShowMessage: (message) => {
			console.log(message);
		}
	});
	return assembler;
	// assembler.localization.ChangeLanguage("zh-cn");		// zh-cn en
	// assembler.platform.ChangePlatform("6502")			// 6502 65c816 z80-gb
}
//#endregion 初始化编译器

//#region 显示所有错误
/**显示所有错误 */
function ShowAllErrors(errors) {
	for (let i = 0; i < errors.length; i++) {
		const error = errors[i];
		console.error(`文件: ${error.filePath} 第 ${error.line} 行 ${error.message}`);
	}
}
//#endregion 显示所有错误

//#region 数据处理
/**
 * 数据处理
 * @param {Int16Array} data 
 */
function ProcessData(data) {
	const result = new Uint8Array(data.length);
	for (let i = 0; i < data.length; i++) {
		if (data[i] < 0)
			result[i] = 0;
		else
			result[i] = data[i];
	}
	return result;
}
//#endregion 数据处理

//#region 编译结果

/**
 * @function ProcessData - 数据处理
 * @param {Int16Array} data
 */

/**
 * @typedef CompileOption - 编译选项
 * @property {string} sourceFile - 要编译的文件
 * @property {string} outputFile - 输出文件
 * @property {string} language - 语言
 * @property {string} platform - 编译平台
 * @property {ProcessData | undefined} ProcessData - 数据处理
 */

/**
 * 编译结果
 * @param {CompileOption} option 
 */
export async function BuildAsm(option) {
	if (option === undefined)
		option = ProcessOption();

	if (!option)
		return;

	option.sourceFile = ProcessFilePath(option.sourceFile);
	option.outputFile = ProcessFilePath(option.outputFile);

	const assembler = await Initialization();
	if (!assembler)
		return;

	if (option.language) assembler.SwitchLanguage(option.language);
	if (option.platform) assembler.SwitchPlatform(option.platform);

	const data = await assembler.fileUtils.ReadFile(option.sourceFile);
	const sourceFileContent = await assembler.fileUtils.BytesToString(data);

	const result = await assembler.CompileText(sourceFileContent, option.sourceFile);
	if (result) {
		option.ProcessData?.(result);
		const fileData = ProcessData(result);
		fs.writeFileSync(option.outputFile, fileData);
	} else {
		// 获取所有错误
		const errors = assembler.diagnostic.GetExceptions();
		ShowAllErrors(errors);
	}

	// 获取所有警告
	const warnings = assembler.diagnostic.GetWarnings();
	ShowAllErrors(warnings);
}

function ProcessOption() {
	let option = {};
	const outMsg = "可输入参数\n-s -source 要编译的代码\n-o -output 输出代码\n-lang 切换语言 zh-cn 或 en\n-p -platform 切换平台，具体请看编译器支持平台";
	if (process.argv.length < 3) {
		console.log(outMsg);
		return;
	}

	let isOutput = false;
	for (let i = 2; i < process.argv.length; i += 2) {
		const arg = process.argv[i + 1];
		switch (process.argv[i]) {
			case "-s":
			case "-source":
				option.sourceFile = arg;
				break;
			case "-o":
			case "-output":
				option.outputFile = arg;
				break;
			case "-lang":
				option.language = arg;
				break;
			case "-p":
			case "-platform":
				option.platform = arg;
				break;
			default:
				if (isOutput)
					break;

				console.log(outMsg);
				isOutput = true;
				break;
		}
	}
	return option;
}

/**处理路径 */
function ProcessFilePath(filePath) {
	if (path.isAbsolute(filePath))
		return filePath;

	return path.join(process.cwd(), filePath);
}
//#endregion 编译结果
